<?php
declare(strict_types=1);

namespace App\Interface\Pay;

use App\Constants\ErrorCode;
use App\Interface\PaymentStrategyInterface;
use App\Model\Contract;
use App\Model\Coupon;
use App\Model\Member;
use App\Model\MemberCoupon;
use App\Model\Normal;
use App\Model\Order;
use App\Model\OrderType;
use App\Model\Special;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Str;
use Util\Common;
use Hyperf\Di\Annotation\Inject;
use Yansongda\Pay\Pay;
use Hyperf\Logger\LoggerFactory;
use Psr\Log\LoggerInterface;


class AliPaymentStrategy implements PaymentStrategyInterface
{
    protected array $config;
    protected RequestInterface $request;
    private $logger;

    #[Inject]
    protected Member $member;
    #[Inject]
    protected OrderType $orderType;

    public function __construct(RequestInterface $request)
    {
        $this->request = $request;
        $this->config = config('pay');
        $log_name = 'alipay' . date('Y-m-d', time());
        $loggerFactory = container()->get(\Hyperf\Logger\LoggerFactory::class);
        $this->logger = $loggerFactory->get($log_name, 'alipay');
    }

    /**支付通用
     * @param array $params
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function pay(array $params): array
    {
        $params = $this->filterParams($params);
        $order_no = Order::generateOrderNumber();
        $member = $this->member->getInfo($this->request);

        if(!$member){
            $member['id'] = 0;
        }
        if (isset($params['price'])) {
            $real_money = $params['price'];
            $model = Order::create([
                'title' => '升级终身会员',
                'type' => OrderType::UP_VIP,
                'member_id' => $member['id'],
                'money' => $real_money,
                'real_money' => $real_money,
                'order_no' => $order_no,
                'pay_type' => Common::ORDER_ALI_PAY,
                'status' => Order::NORMAL,
                'bd_userid' => $params['userid'],
                'bd_planid' => $params['planid'],
                'bd_unitid' => $params['unitid'],
                'bd_keywordid' => $params['keywordid'],
                'version' => 1,
                'pay_ip' => Normal::getRealIp($this->request),
            ]);
        } elseif (isset($params['special_id'])) {
            $specialModel = Special::where('id', $params['special_id'])
                ->first();
            if (!$specialModel) {
                return array('code' => ErrorCode::PARAMS_ERR);
            }
            $real_money = $specialModel->price;
            $model = Order::create([
                'title' => '觅合同-购买专题',
                'type' => OrderType::SPECIAL,
                'member_id' => $member['id'] ?? null,
                'money' => $real_money,
                'real_money' => $real_money,
                'order_no' => $order_no,
                'pay_type' => Common::ORDER_ALI_PAY,
                'status' => Order::NORMAL,
                'bd_userid' => $params['userid'],
                'bd_planid' => $params['planid'],
                'bd_unitid' => $params['unitid'],
                'bd_keywordid' => $params['keywordid'],
                'version' => 1,
                'pay_ip' => Normal::getRealIp($this->request),
                'special_id' => $specialModel->id,
                'keyword' => $params['keyword'],
                'bd_vid' => $params['bd_vid']
            ]);
        } else {
            $pay_info = $this->orderType->where('id', $params['payid'])->first();
            if ($pay_info->type == OrderType::NORMAL_TYPE && !$member) {
                return array('code' => ErrorCode::UNKNOW_INFO);
            }
            if ($pay_info->type == OrderType::RECEIVING) {
                if (!$this->validateReceiving($params)) {
                    return array('code' => ErrorCode::INVALID_RECEIVING);
                }
            }
            if (isset($params['coupon_id']) && $params['coupon_id'] > 0 && $pay_info->type < OrderType::UP_VIP) {
                $realArray = $this->useConpou((int)$params['coupon_id'], (int)$pay_info['price']);
                if ($realArray['code'] != ErrorCode::SUCCESS) {
                    return $realArray;
                }
                $real_money = $realArray['real_money'];
            } else {
                $params['coupon_id'] = null;
                $real_money = $pay_info->price;
            }
            $model = Order::create([
                'title' => $pay_info->tag,
                'type_id' => $pay_info->id,
                'type' => $pay_info->type,
                'member_id' => $member['id'] ?? null,
                'money' => $pay_info->price,
                'real_money' => $real_money,
                'order_no' => $order_no,
                'pay_type' => Common::ORDER_ALI_PAY,
                'member_coupon_id' => $params['coupon_id'],
                'status' => Order::NORMAL,
                'receiving' => $params['receiving'] ?? null,
                'bd_userid' => $params['userid'],
                'bd_planid' => $params['planid'],
                'bd_unitid' => $params['unitid'],
                'bd_keywordid' => $params['keywordid'],
                'bd_vid' => $params['bd_vid'],
                'version' => 1,
                'pay_ip' => Normal::getRealIp($this->request),
                'contract_id' => $params['contract_id'] ?? null,
                'keyword' => $params['keyword']
            ]);
        }
        $class = Str::studly($params['type_mode']);
        return $this->$class($model, $params);
    }

    /**订单列表去支付
     * @param array $params
     * @return array
     */
    public function payNow(array $params): array
    {
        $orderModel = Order::where('order_no', $params['order_no'])->first();
        if (!$orderModel) {
            return array('code' => ErrorCode::PARAMS_ERR, 'msg' => '订单不存在');
        }
        if ($orderModel->status != Order::NORMAL) {
            return array('code' => ErrorCode::PARAMS_ERR, 'msg' => '订单不可被支付');
        }
        if (isset($params['coupon_id']) && !$orderModel->member_coupon_id) {
            $realArray = $this->useConpou((int)$params['coupon_id'], (int)$orderModel->money);
            if ($realArray['code'] != ErrorCode::SUCCESS) {
                return $realArray;
            }
            $real_money = $realArray['real_money'];
            $orderModel->member_coupon_id = $params['coupon_id'];
        } else {
            $real_money = $orderModel->money;
        }
        $orderModel->real_money = $real_money;
        $orderModel->save();
        $class = Str::studly($params['type_mode']);
        return $this->$class($orderModel, $params);
    }

    /**pc支付
     * @param $orderModel
     * @param array $params
     * @return array
     */
    public function pcPay($orderModel, array $params): array
    {
        $this->config['alipay']['default']['return_url'] = $params['host'];
        if (!$params['return_url']) {
            if ($orderModel->type == OrderType::SPECIAL) {
                $specialModel = Special::where('id', $orderModel->special_id)->first();
                $this->config['alipay']['default']['return_url'] ='https://'. Common::MAIN_HOST. '/download?out_trade_no=' .$orderModel->order_no;
            }else {
                if ($orderModel->type == OrderType::ONE_TYPE) {
                    $contractModel = Contract::where('id', $orderModel->contract_id)->first();
                    $this->config['alipay']['default']['return_url'] = 'https://'.Common::MAIN_HOST. '/download?out_trade_no=' .$orderModel->order_no;
                }
            }
        } else {
            $this->config['alipay']['default']['return_url'] = $params['return_url'];
        }
        Pay::config(array_merge($this->config,['_force'=>true]));
        $result = Pay::alipay()->web([
            'out_trade_no' => $orderModel->order_no,
            'total_amount' => $orderModel->real_money / 100,
            'subject' => $orderModel->title,
        ]);
        return array('code' => ErrorCode::SUCCESS, 'data' => (string)$result->getBody());
    }

    /**wap支付
     * @param $orderModel
     * @param array $params
     * @return array
     */
    public function wapPay($orderModel, array $params): array
    {
//        if(!isset($params['return_url']) || !$params['return_url']){
//            $payInfo = OrderType::where('id', $orderModel->type_id)->first();
//            if ($payInfo && $payInfo->type == OrderType::ONE_TYPE) {
//                $contractModel = Contract::where('id', $orderModel->contract_id)->first();
//                $this->config['alipay']['default']['return_url'] .= '/contractdetail/'.$orderModel->contract_id.'.html?path='.$contractModel->path;
//            }
//            if ($orderModel->special_id > 0 ) {
//                $specialModel = Special::where('id', $orderModel->special_id)->first();
//                $this->config['alipay']['default']['return_url'] .= '/wap/special-detail?id='.$specialModel->id.'&path='.$specialModel->zip;
//            }
//        }else{

//        }
        $this->config['alipay']['default']['return_url'] = $params['host'];
        if (isset($params['return_url']) && $params['return_url']) {
            $this->config['alipay']['default']['return_url'] = $params['return_url'];
        }
        Pay::config(array_merge($this->config,['_force'=>true]));
        $result = Pay::alipay()->wap([
            'out_trade_no' => $orderModel->order_no,
            'total_amount' => $orderModel->real_money / 100,
            'subject' => $orderModel->title,
            'quit_url' => $this->config['alipay']['default']['return_url']
        ]);
        return array('code' => ErrorCode::SUCCESS, 'data' => (string)$result->getBody(), 'order' => $orderModel->order_no);
    }

    public function __call($name, $arguments)
    {
        // 处理不存在的实例方法调用
        return '';
    }

    /**支付宝回调
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     */
    public function notify(): bool
    {
        $pay = Pay::alipay($this->config);
        $data = $pay->callback($this->request);
        $this->logger->info(json_encode($data));
        if ($data['trade_status'] == 'TRADE_SUCCESS') {
            Order::handle($data['out_trade_no'],
                $data['trade_no']);
            $pay->success();
            return true;
        }
        return false;
    }

    /**同步关闭订单
     * @param string $order_no
     * @return void
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
     */
    public function cancel(string $order_no)
    {
        $order_close = [
            'out_trade_no' => $order_no,
        ];
        return Pay::alipay($this->config)->close($order_close);
    }


    /**整理参数
     * @param array $params
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function filterParams(array $params): array
    {
        if (!array_key_exists('bd_vid', $params)) {
            $params['bd_vid'] = null;
        }
        if (!array_key_exists('keyword', $params)) {
            $params['keyword'] = null;
        }
        if (!array_key_exists('userid', $params)) {
            $params['userid'] = null;
        }
        if (!array_key_exists('planid', $params)) {
            $params['planid'] = null;
        }
        if (!array_key_exists('unitid', $params)) {
            $params['unitid'] = null;
        }
        if (!array_key_exists('keywordid', $params)) {
            $params['keywordid'] = null;
        }
        if (isset($params['contract_id']) && $params['contract_id'] && $params['contract_id']) {
            $title = Contract::where('id', $params['contract_id'])->value('title');
            redis()->zincrby(Common::ORDER_RANK_LIST, 1, $title);
        }else{
            $params['contract_id'] = 0;
        }
        return $params;
    }

    /**验证定制合同表单内容
     * @param $params
     * @return bool
     */
    public function validateReceiving($params): bool
    {
        if (isset($params['receiving'])) {
            if (!is_array($params['receiving'])) {
                $params['receiving'] = json_decode($params['receiving'], true);
            }
            if (!$params['receiving']['name']) {
                return false;
            }
            if (!$params['receiving']['phone'] && !$params['receiving']['email']) {
                return false;
            }
            return true;
        }
        return false;
    }

    /**使用优惠券
     * @param int $couponId
     * @param $payInfo
     * @return array
     */
    public function useConpou(int $couponId, int $payPrice): array
    {
        $MemberCoupon = MemberCoupon::where('id', $couponId)->first();
        $coupon = Coupon::where('id', $MemberCoupon->coupon_id)->first();
        if ($payPrice < $coupon->fill_price) {
            return array('code' => ErrorCode::ORDER_COUPON_ERROR);
        }
        $now = time();
        if ($MemberCoupon->status != MemberCoupon::NORMAL || $now > $MemberCoupon->end) {
            return array('code' => ErrorCode::ORDER_COUPON_ERROR);
        }
        $MemberCoupon->status = MemberCoupon::USED;
        $MemberCoupon->save();
        return array('code' => ErrorCode::SUCCESS, 'real_money' => $payPrice - $coupon->price);
    }

}
